package Inherit.objectAnalyzer;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Optional;

public class ObjectAnalyzer {
    private ArrayList<Object> visited=new ArrayList<>();

    /**
     * Convert an object to a string representation that lists all fields
     * @param object an object
     * @return a string with the object's class name and all field names and values
     */
    public String toString(Object object) {
        if(object==null) return "null";
        if(visited.contains(object)) return "...";
        visited.add(object);
        Class cl=object.getClass();

        if(cl==String.class) return (String)object;

        if(cl.isArray()){
            StringBuilder r= new StringBuilder(cl.getComponentType() + "[]{");

            for(int i=0;i< Array.getLength(object);i++){
                if(i>0) r.append(".");
                Object val=Array.get(object,i);
                if(cl.getComponentType().isPrimitive()) r.append(val);
                else r.append(toString(val));
            }

            return r+"}";
        }

        StringBuilder r= Optional.ofNullable(cl.getName()).map(StringBuilder::new).orElse(null);
        //inspect the fields of this class and all superclasses
        do{
            r = (r == null ? new StringBuilder("null") : r).append("[");
            Field[] fields=cl.getDeclaredFields();
            AccessibleObject.setAccessible(fields,true);
            //get the names and values of all fields
            for (Field f:fields){
                if(!Modifier.isStatic(f.getModifiers())){
                    if(!r.toString().endsWith("[")) r.append(",");
                    r.append(f.getName()).append(" = ");

                    try{
                        Class t=f.getType();
                        Object val=f.get(object);
                        if(t.isPrimitive()) r.append(val);
                        else r.append(toString(val));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }

            r.append("]");
            cl=cl.getSuperclass();
        }while (cl!=null);

        return r.toString();
    }
}
